home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Expert
/
Windows Expert.iso
/
windownt
/
ntls.zip
/
LS.CPP
next >
Wrap
C/C++ Source or Header
|
1993-03-06
|
18KB
|
572 lines
// ls - Windows NT directory listing utility
//
// Author: Jon S. Whalen (c) 1993
// internet: jon@hook.corp.mot.com
// compuserve: 76665,3043
//
// 6 March 1993
// Release 1.0 'ls.exe'
#include <windef.h>
#include <excpt.h>
#include <winbase.h>
#include <iostream.h>
#include <stdlib.h>
#include <winuser.h>
//#include <wincon.h>
// the structs and functions are declared in
// wincon.h, but not for C++, so they're included here to get
// the linkage to work.
typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD;
typedef struct _SMALL_RECT {
SHORT Left;
SHORT Top;
SHORT Right;
SHORT Bottom;
} SMALL_RECT, *PSMALL_RECT;
typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
COORD dwSize;
COORD dwCursorPosition;
WORD wAttributes;
SMALL_RECT srWindow;
COORD dwMaximumWindowSize;
} CONSOLE_SCREEN_BUFFER_INFO, *PCONSOLE_SCREEN_BUFFER_INFO;
extern "C" BOOL WINAPI GetConsoleScreenBufferInfo( HANDLE, PCONSOLE_SCREEN_BUFFER_INFO );
extern "C" BOOL WINAPI SetConsoleCursorPosition( HANDLE, COORD );
// error/usage message
void Usage( void )
{
cerr << "\nProgram: \"ls.exe\" - Windows NT directory list utility - Version 1.0" << endl;
cerr << " Copyright (c) Jon S. Whalen 1993. All rights reserved." << endl;
cerr << "\nusage: ls [-1?alstzLSTFZ] [path|file|pattern]\n" << endl;
cerr << " ?|h: display this usage message" << endl;
cerr << " 1: format as single column, left adjusted" << endl;
cerr << " a: show all files (including .* and hidden files)" << endl;
cerr << " F: add suffixes to the file names:" << endl;
cerr << " '\\' = directory" << endl;
cerr << " '!' = hidden file (only when -a is specified)" << endl;
cerr << " '&' = system file" << endl;
cerr << " l: use long listing format" << endl;
cerr << " L: use longer listing format" << endl;
cerr << " s: sort by size - decreasing" << endl;
cerr << " S: sort by size - increasing" << endl;
cerr << " t: sort by modification time - newest first" << endl;
cerr << " T: sort by modification time - oldest first" << endl;
cerr << " z: sort by name - lexical order (i.e. alphabetical order)" << endl;
cerr << " Z: sort by name - reverse lexical order" << endl;
cerr << "\nNotes:\n" << endl;
cerr << " 1. For compatibility with Unix ls, file and directory names beginning" << endl;
cerr << " with '.' are not displayed unless the -a option is specified." << endl;
cerr << " 2. Specifiying only a drive name (e.g. \"ls C:\") will list the contents" << endl;
cerr << " of the current working directory for that drive." << endl;
cerr << " 3. File systems which are case-insensitive (e.g. FAT) are displayed" << endl;
cerr << " in lower case. Case-sensitive file systems (e.g. NTFS) are displayed" << endl;
cerr << " in mixed upper and lower case. It is Unicode compatible." << endl;
cerr << " 4. This program is freely distributable and is provided \"AS-IS\", WITHOUT" << endl;
cerr << " WARRANTY of any kind, either express or implied. No guarantee is made" << endl;
cerr << " of suitablility for any purpose, whatsoever." << endl;
}
struct FileListEl {
WIN32_FIND_DATA *lpwfd;
FileListEl *next, *prev;
FileListEl( void ) : lpwfd(0), next(0), prev(0) { }
~FileListEl( void ) { if( lpwfd ) delete lpwfd; }
};
void SwapEl( FileListEl * cur, FileListEl *next )
{
FileListEl * p1 = (cur?cur->prev:0);
FileListEl * p2 = cur;
FileListEl * p3 = next;
FileListEl * p4 = (p3?p3->next:0);
if( p1 ) p1->next = p3;
p3->prev = p1;
if( p4 ) p4->prev = p2;
p2->next = p4;
p3->next = p2;
p2->prev = p3;
}
int GetFileList( TCHAR * filter, FileListEl *& head, DWORD & max_filename_len )
{
FileListEl * cur = 0;
WIN32_FIND_DATA * lpwfd;
int matches = 0;
DWORD len = 0;
lpwfd = new WIN32_FIND_DATA;
HANDLE hSearch = FindFirstFile( filter, lpwfd );
if( hSearch == INVALID_HANDLE_VALUE )
{
return 0;
}
// else
cur = head = new FileListEl;
head->lpwfd = lpwfd;
max_filename_len = lstrlen(lpwfd->cFileName);
matches = 1;
lpwfd = new WIN32_FIND_DATA;
while( FindNextFile( hSearch, lpwfd ) )
{
cur->next = new FileListEl; cur->next->prev = cur; cur = cur->next;
cur->lpwfd = lpwfd;
len = lstrlen(lpwfd->cFileName);
if( max_filename_len < len ) max_filename_len = len;
lpwfd = new WIN32_FIND_DATA;
matches++;
}
delete lpwfd;
FindClose( hSearch );
return matches;
}
int main( int argc, TCHAR **argv )
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
TIME_ZONE_INFORMATION tzi;
TCHAR filter[512]; filter[0] = 0;
TCHAR cur_directory[512]; cur_directory[0] = 0;
TCHAR new_directory[512]; new_directory[0] = 0;
TCHAR * cp = 0;
DWORD len = 0;
DWORD maxlen = 512;
DWORD max_filename_len = 0;
LPTSTR progname = argv[0];
FileListEl * head = 0;
FileListEl * cur = 0;
DWORD pos = 0;
int column = 0;
int num_columns = 0;
// Flags
int f_list_all = 0;
int f_long_list = 0;
int f_modify_time_sort = 0;
int f_alpha_sort = 1;
int f_size_sort = 0;
int f_list_with_suffix = 0;
int f_single_column = 0;
int error = 0;
int suffixed = 0;
int case_sensitive = 0;
int matches = 0;
long result = 0;
// open a handle to the console
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
// check out the environment
result = GetCurrentDirectory( maxlen, cur_directory );
result = GetConsoleScreenBufferInfo(hOutput, &csbi);
result = GetTimeZoneInformation(&tzi);
DWORD line_length = csbi.dwSize.X;
// process command line args
argc--; argv++; // skip progname
for ( ; argc && ((*argv)[0] == L'/' || (*argv)[0] == L'-'); argv++, argc-- )
{
cp = *argv; cp++;
while( *cp )
{
switch( *cp )
{
case L'h':
case L'?':
Usage();
return -1;
break;
case L'1':
f_single_column++;
break;
case L'a':
f_list_all++;
break;
case L'l':
f_long_list = 1;
break;
case L'L':
f_long_list = 2;
break;
case L's':
f_size_sort = 1;
f_alpha_sort = 0;
f_modify_time_sort = 0;
break;
case L'S':
f_size_sort = -1;
f_alpha_sort = 0;
f_modify_time_sort = 0;
break;
case L't':
f_modify_time_sort = 1;
f_alpha_sort = 0;
f_size_sort = 0;
break;
case L'T':
f_modify_time_sort = -1;
f_alpha_sort = 0;
f_size_sort = 0;
break;
case L'F':
f_list_with_suffix++;
break;
case L'z':
f_alpha_sort = 1;
f_modify_time_sort = 0;
f_size_sort = 0;
break;
case L'Z':
f_alpha_sort = -1;
f_modify_time_sort = 0;
f_size_sort = 0;
break;
default:
cerr << "ls: illegal option -- " << *cp << endl;
error++;
}
cp++;
}
}
if( error )
{
Usage( );
return -1;
}
if( argc == 0 )
{
filter[0] = L'*';
filter[1] = L'.';
filter[2] = L'*';
filter[3] = 0;
}
else
{
// check to see if the argument specifies a path
lstrcpy( filter, *argv );
long index = lstrlen( filter );
switch( filter[index - 1] )
{
case L':':
case L'\\':
filter[index] = L'*';
filter[index + 1] = L'.';
filter[index + 2] = L'*';
filter[index + 3] = 0;
break;
}
}
// get drive information
DWORD dwMaxFilename, dwFlags;
TCHAR file_system_name[32];
TCHAR volume_name[128];
DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
DWORD free_bytes, total_bytes;
if( filter[1] == L':' )
{
TCHAR tmp[4];
tmp[0] = filter[0]; tmp[1] = filter[1]; tmp[2] = L'\\'; tmp[3] = 0;
GetVolumeInformation( tmp, volume_name, 128, 0, &dwMaxFilename, &dwFlags, file_system_name, 32 );
GetDiskFreeSpace( tmp, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
}
else
{
GetVolumeInformation( 0, volume_name, 128, 0, &dwMaxFilename, &dwFlags, file_system_name, 32 );
GetDiskFreeSpace( 0, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
}
if( dwFlags & FS_CASE_IS_PRESERVED )
case_sensitive++;
total_bytes = total_clusters * sectors_per_cluster * bytes_per_sector;
free_bytes = free_clusters * sectors_per_cluster * bytes_per_sector;
// first find all matching files
matches = GetFileList( filter, head, max_filename_len );
if( !matches )
{
cout << filter << " not found." << endl;
return 0;
}
else if( matches == 1 && (head->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) )
{
delete head; head = 0;
// the filter was a directory name, add \*.* to the filter
long index = lstrlen( filter );
filter[index] = L'\\';
filter[index + 1] = L'*';
filter[index + 2] = L'.';
filter[index + 3] = L'*';
filter[index + 4] = 0;
// now try again
matches = GetFileList( filter, head, max_filename_len );
}
if( f_single_column )
num_columns = 1;
else
num_columns = line_length/(max_filename_len + 4);
// now sort
if( f_modify_time_sort )
{
// this is a dumb sorting algorithm -- I'll replace it soon?
int swapped_one = 1;
while( swapped_one )
{
swapped_one = 0;
for( cur = head; cur && cur->next; cur = cur->next )
{
result = CompareFileTime( &(cur->lpwfd->ftLastWriteTime), &(cur->next->lpwfd->ftLastWriteTime) );
if( f_modify_time_sort < 0 ) result *= -1;
if( result == -1 )
{
// swap the entries
swapped_one++;
FileListEl * next = cur->next;
SwapEl( cur, next );
if( head == cur ) head = next;
cur = next;
}
}
}
}
else if( f_size_sort )
{
// this is a dumb sorting algorithm -- I'll replace it soon?
int swapped_one = 1;
while( swapped_one )
{
swapped_one = 0;
for( cur = head; cur && cur->next; cur = cur->next )
{
if( (cur->lpwfd->nFileSizeLow) < (cur->next->lpwfd->nFileSizeLow) )
result = -1;
else if ( (cur->next->lpwfd->nFileSizeLow) == (cur->lpwfd->nFileSizeLow) )
result = 0;
else
result = 1;
if( f_size_sort < 0 ) result *= -1;
if( result == -1 )
{
// swap the entries
swapped_one++;
FileListEl * next = cur->next;
SwapEl( cur, next );
if( head == cur ) head = next;
cur = next;
}
}
}
}
else if( f_alpha_sort )
{
// this is a dumb sorting algorithm -- I'll replace it soon?
int swapped_one = 1;
while( swapped_one )
{
swapped_one = 0;
for( cur = head; cur && cur->next; cur = cur->next )
{
result = lstrcmp( (cur->next->lpwfd->cFileName), (cur->lpwfd->cFileName) );
if( f_alpha_sort < 0 ) result *= -1;
if( result == -1 )
{
// swap the entries
swapped_one++;
FileListEl * next = cur->next;
SwapEl( cur, next );
if( head == cur ) head = next;
cur = next;
}
}
}
}
// print the listing
if ( f_long_list )
{
if( f_long_list > 1 )
{
cout << "\nVolume Name: \"" << volume_name << "\" File System Type: [" << file_system_name << "]" << endl;
cout << "\n[Attribs] [Size] [Created] [Last Modified] [Name]" << endl;
}
else
cout << "\n[Attribs] [Size] [Last Modified] [Name]" << endl;
for( cur = head; cur; cur = cur->next )
{
if ( f_list_all || (cur->lpwfd->cFileName[0] != L'.' && !(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)) )
{
SYSTEMTIME stm;
TCHAR buffer[128];
// attributes
cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) ? 'd':'-');
cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) ? 'h':'-');
cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_SYSTEM) ? 's':'-');
cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_READONLY) ? 'r':'-');
cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_ARCHIVE) ? 'a':'-');
// attributes for NTFS only
cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_TEMPORARY) ? 't':'-');
cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_ATOMIC_WRITE) ? 'm':'-');
cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_XACTION_WRITE) ? 'x':'-');
cout << " ";
// size
wsprintf( buffer, "%wc%9d ", ((cur->lpwfd->nFileSizeHigh)?L'+':L' '), cur->lpwfd->nFileSizeLow );
cout << buffer;
if( f_long_list > 1 )
{
// creation time
FileTimeToSystemTime( &(cur->lpwfd->ftCreationTime), &stm);
wsprintf( buffer, " %02d-%02d-%02d %02d:%02d:%02d ", stm.wMonth, stm.wDay, (stm.wYear%100), (stm.wHour - tzi.Bias/60), stm.wMinute, stm.wSecond );
cout << buffer;
// last access time
//FileTimeToSystemTime( &(cur->lpwfd->ftLastAccessTime), &stm);
//wsprintf( buffer, " %02d-%02d-%02d %02d:%02d:%02d ", stm.wMonth, stm.wDay, (stm.wYear%100), (stm.wHour - tzi.Bias/60), stm.wMinute, stm.wSecond );
//cout << buffer;
}
// last modification time
FileTimeToSystemTime( &(cur->lpwfd->ftLastWriteTime), &stm);
wsprintf( buffer, " %02d-%02d-%02d %02d:%02d:%02d ", stm.wMonth, stm.wDay, (stm.wYear%100), (stm.wHour - tzi.Bias/60), stm.wMinute, stm.wSecond );
cout << buffer;
cout << (case_sensitive?cur->lpwfd->cFileName:CharLower(cur->lpwfd->cFileName));
if( f_list_with_suffix )
{
if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
cout << L'\\';
else
{
if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)
cout << L'!';
if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_SYSTEM)
cout << L'&';
}
}
cout << endl;
}
}
if( f_long_list > 1 )
{
cout << "\nVolume Statistics:" << endl;
cout << "\n[Size] " << total_bytes << " [Free] " << free_bytes <<" [% Used] " << 100.00*(long)(total_bytes - free_bytes)/(long)total_bytes << "." << endl;
//cout << "bytes used: " << (total_bytes - free_bytes) endl;
}
} // end-if
else
for( cur = head; cur; cur = cur->next )
{
if ( f_list_all || (cur->lpwfd->cFileName[0] != L'.' && !(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)) )
{
len = lstrlen(cur->lpwfd->cFileName);
if( column == num_columns )
{
cout << endl;
column = 1;
}
else
column++;
// filename
cout << (case_sensitive?cur->lpwfd->cFileName:CharLower(cur->lpwfd->cFileName));
pos += len;
// suffix
suffixed = 0;
if( f_list_with_suffix )
{
if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
{
cout << L'\\';
suffixed++;
}
else
{
if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)
{
cout << L'!';
suffixed++;
}
if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_SYSTEM)
{
cout << L'&';
suffixed++;
}
}
pos++;
}
// padding
len = max_filename_len - len + 4 - suffixed;
if( column < num_columns )
while( len-- ) cout << ' ';
}
}
return 0;
}